.\" $assl: assl.3,v 1.14 2009/12/23 03:53:17 marco Exp $
.\"
.\" Copyright (c) 2009 Marco Peereboom <marco@peereboom.us>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: December 23 2009 $
.Dt ASSL 3
.Os
.Sh NAME
.Nm assl
.Nd agglomerated SSL
.Sh SYNOPSIS
.Fd #include <assl.h>
.Ft void
.Fn assl_initialize "void"
.Ft struct assl_context	*
.Fn assl_alloc_context "enum assl_method method" "int flags"
.Ft int
.Fn assl_load_file_certs "struct assl_context *ctx" "char *ca" "char *cert" "char *key"
.Ft int
.Fn assl_connect "struct assl_context *ctx" "char *host" "char *port" "int flags"
.Ft int
.Fn assl_serve "char *host" "char *port" "int flags" "void (*callback)(int sock)"
.Ft int
.Fn assl_accept "struct assl_context *ctx" "int sock"
.Ft ssize_t
.Fn assl_read "struct assl_context *ctx" "void *buf" "size_t nbytes"
.Ft ssize_t
.Fn assl_write "struct assl_context *ctx" "void *buf" "size_t nbytes"
.Ft int
.Fn assl_poll "struct assl_context *ctx" "int mseconds" "short event" "short *revents"
.Ft int
.Fn assl_close "struct assl_context *ctx"
.Ft void
.Fn assl_fatalx "char *errstr"
.Sh DESCRIPTION
.Fn assl_initialize
prepares the library for first use.
This function must be called before any other function is called.
.Pp
.Fn assl_alloc_context
allocates an
.Nm
context.
A context contains all SSL/TLS connection specific details.
The
.Fa method
parameter indicates what SSL/TLS type and version to use for the context.
Possible
.Fa method
values are:
.Bl -tag -width "ASSL_M_TLSV1_SERVER" -offset indent -compact
.It Cm ASSL_M_SSLV2
SSL V2 client or server connection.
.It Cm ASSL_M_SSLV2_CLIENT
SSL V2 client connection.
.It Cm ASSL_M_SSLV2_SERVER
SSL V2 server connection.
.It Cm ASSL_M_SSLV3
SSL V3 client or server connection.
.It Cm ASSL_M_SSLV3_CLIENT
SSL V3 client connection.
.It Cm ASSL_M_SSLV3_SERVER
SSL V3 server connection.
.It Cm ASSL_M_TLSV1
TLS V1 client or server connection.
.It Cm ASSL_M_TLSV1_CLIENT
TLS V1 client connection.
.It Cm ASSL_M_TLSV1_SERVER
TLS V1 server connection.
.It Cm ASSL_M_ALL
Any version of a client or server connection.
.It Cm ASSL_M_ALL_CLIENT
Any version of a client connection.
.It Cm ASSL_M_ALL_SERVER
Any version of a server connection.
.El
.Pp
If
.Fa flags
is set to ASSL_F_CHILD then
.Fn assl_fatalx
will halt execution using
.Xr _exit 2
instead of
.Xr exit 3
per
.Xr fork 2
requirement.
This flag shall be set for all forked contexts.
.Pp
The function will return NULL to indicate failure.
.Pp
.Fn assl_load_file_certs
loads all required keys and certificates to authenticate a client or server.
.Fa cert
and
.Fa key
contain the certificate and key required to authenticate the
calling machine to the remote machine.
.Fa ca
contains the Certificate Authority certificate.
All files must be provided in PEM format.
The
.Fa cert
is validated against the
.Fa key .
Providing a CA is required.
The function returns a non-zero value to indicate failure.
.Pp
.Fn assl_connect
tries to establish an SSL/TLS connection to a
.Fa host
and
.Fa port .
The
function returns a non-zero value to indicate failure.
More precisely, 1 for libc failures and \-1 for
.Xr openssl 1
failures.
The caller is responsible for calling
.Fn assl_close
to unwind the context.
If
.Fa flags
is set to ASSL_F_NONBLOCK then the socket will be set up as non-blocking.
.Pp
.Fn assl_serve
is a blocking function that sets up a listening socket that waits for
incoming connections on
.Fa host
and
.Fa port .
Once an incoming connection is detected it will call
.Fa callback
with the appropriate socket.
It is the responsibility of the callback function to either fork and set up
a context.
Both
.Fa host
and
.Fa port
can be NULL.
In the
.Fa host
case the server will listen on all possible IP addresses and in the
.Fa port
case the server will listen on port 4433.
The
.Fa flags
parameter is a bitwise field and can be set to:
.Bl -tag -width "ASSL_F_CLOSE_SOCKET" -offset indent -compact
.It Cm ASSL_F_NONBLOCK
Set the socket to non-block.
.It Cm ASSL_F_CLOSE_SOCKET
Close the socket upon return from the callback.
This is to facilitate forking applications.
.El
To make
.Fn assl_serve
exit set the global variable
.Fa assl_stop_serving
to true and interrupt the underlying
.Xr poll 2
function.
.Pp
.Fn assl_accept
is the equivalent of the
.Xr accept 2
function with the added SSL/TLS handshake and certificate validation
functionality.
This function should be called from the
.Fa callback
to
.Fn assl_serve
after a context has been allocated in said function.
The function returns a non-zero value to indicate failure.
.Pp
.Fn assl_read
will read
.Fa nbytes
into
.Fa buf
from the
.Fa ctx
socket.
In blocking mode the function will not return until
.Fa nbytes
have been read or an error condition occurred.
In non-blocking mode the function will return \-1 and errno = EAGAIN
to indicate that there was no data ready to read.
All other errors simply return
.Fa nbytes
= \-1.
Upon success the function returns the number of bytes read.
.Pp
.Fn assl_write
will write
.Fa nbytes
from
.Fa buf
to the
.Fa ctx
socket.
In blocking mode the function will not return until
.Fa nbytes
have been written or an error condition occurred.
In non-blocking mode the function will return \-1 and errno = EAGAIN
to indicate that data could not be written immediately.
All other errors simply return
.Fa nbytes
= \-1.
Upon success the function returns the number of bytes written.
.Pp
.Fn assl_poll
polls the socket in
.Fa ctx
for up to
.Fa mseconds
milliseconds for
.Fa event
to occur.
An
.Fa mseconds
timeout of 0 will return immediately and INFTIM will block indefinitely.
If
.Fa revents
is not NULL it returns the
.Fa revents
field from the pollfd structure as returned by the
.Xr poll 2
command.
.Fn assl_poll
returns 0 to indicate a timeout condition, \-1 for error conditions and 1
for success.
The return value of 1 really is the number of file descriptors that are
ready and this mimics the
.Xr poll 2
semantics.
.Pp
.Fn assl_close
function terminates all connections and unwinds all resources, including
context memory.
Do not use the context pointer after calling this function.
It is recommended to set the context pointer to NULL after this call.
.Pp
.Fn assl_fatalx
prints
.Fa errstr
and exits.
If the library is compiled with ASSL_NO_FANCY_ERRORS then it will not
record the calling stack.
The error handling code is not thread or re-entrant safe.
It was written to accommodate finite state machines instead.
.Sh EXAMPLES
The following code fragment illustrates the client case:
.Bd -literal -offset indent
#include "assl.h"

int
main(int argc, char *argv[])
{
	struct assl_context	*c;

	assl_initialize();

	c = assl_alloc_context(ASSL_M_TLSV1_CLIENT);
	if (c == NULL)
		assl_fatalx("assl_alloc_context");

	if (assl_load_file_certs(c, "../ca/ca.crt",
	    "client/client.crt", "client/private/client.key"))
		assl_fatalx("assl_load_certs");

	if (assl_connect(c, "localhost", ASSL_DEFAULT_PORT,
	    ASSL_F_BLOCK))
		assl_fatalx("assl_connect");

	return (0);
}
.Ed
.Pp
The following code fragment illustrates the server case:
.Bd -literal -offset indent
#include "assl.h"

void			serve_callback(int);

void
serve_callback(int s)
{
	struct assl_context	*c;

	c = assl_alloc_context(ASSL_M_TLSV1_SERVER);
	if (c == NULL)
		assl_fatalx("assl_alloc_context");

	if (assl_load_file_certs(c, "../ca/ca.crt",
	    "server/server.crt", "server/private/server.key"))
		assl_fatalx("assl_load_file_certs");

	if (assl_accept(c, s))
		assl_fatalx("assl_accept");

	errx(1, "do something!");
}

int
main(int argc, char *argv[])
{
	assl_initialize();

	assl_serve(NULL, ASSL_DEFAULT_PORT,
	    ASSL_F_BLOCK, serve_callback);

	return (0);
}
.Ed
.Sh DON'T SEE ALSO
.Xr openssl 1
.Sh HISTORY
.An -nosplit
.Pp
.Nm
was written by
.An Marco Peereboom Aq marco@peereboom.us
in order to hide the awful OpenSSL API.
It strives to reuse
.Xr openssl 1
APIs and provide a much simpler and sane interface for programmers that are
interested in writing applications that require the SSL/TLS protocol for
secure communications.
.Pp
Once the API solidifies, individual functions can be replaced with code that
does not rely on
.Xr openssl 1
